home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 11 / AMUG BBS in a Box Volume XI (April 1994) (MacWizards).iso / Files / Tele / Pete Johnson / Mehit 3.0.b15<source>.sit / UserLog.p < prev   
Encoding:
Text File  |  1991-07-11  |  17.5 KB  |  536 lines  |  [TEXT/PJMM]

  1. unit UserLog;
  2.  
  3. {    Unit to backup, sort and zero user minutes in a Red Ryder Host UserLog        }
  4. {    and to reset CallerLog and TabbyLog.                                    }
  5.  
  6. {    Written by Pete Johnson for the Glassell Park BBS 213-254-4133                }
  7.  
  8. {    Date of last revision: April 14, 1991                                    }
  9.  
  10.  
  11. interface
  12.  
  13. uses
  14.     Globals, HelloTabby, mehitFile, LogUtils;
  15.  
  16. type
  17.  
  18.     OldNum = longint;
  19.     MNA = record
  20.             HowMany: longint;
  21.             OldNumbers: array[1..1] of OldNum;
  22.         end;
  23.     MNAPtr = ^MNA;
  24.     MNAHdl = ^MNAPtr;
  25.  
  26. var
  27.     myMNAHdl: MNAHdl;
  28.     ULRecSize: longint;
  29.  
  30.  
  31. procedure ProcessUserLog;
  32.  
  33. implementation
  34.  
  35. type
  36.     WhenCalled = packed array[1..6] of char;
  37.     UserRecord = packed record
  38.             FirstName: string[15];
  39.             LastName: string[15];
  40.             CallingFromAndPW: packed array[1..40] of char;
  41.             NumberOfCalls: integer;
  42.             DateLastCalled: WhenCalled;
  43.             TCMRRF: packed array[1..6] of char;    {Time, Clearance, Minutes last call, Reserved, Reserved, Flags}
  44.             Uploads: integer;
  45.             Downloads: integer;
  46.             PrivMsg: integer;
  47.             PubMsg: integer;
  48.             MRRF: packed array[1..6] of char;
  49.             HiMsgRead: longint;
  50.             CombinedReads: packed array[1..32] of char
  51.         end;
  52.  
  53. const
  54.     DELETED = 64;
  55.  
  56. {-----------------------------------------------------------------    }
  57.  
  58. function StripTime (inString: str255): str255;
  59.  
  60. {    turns standard DateString of 04/01/91 1:00:06 into 04/01/91 }
  61.  
  62.     begin
  63.         StripTime := copy(inString, 1, pos(' ', inString) - 1);
  64.     end;
  65.  
  66. {-----------------------------------------------------------------    }
  67.  
  68.     var
  69.         ThisUser: UserRecord;
  70.         DialogPointer: DialogPtr;
  71.         fndrInfo: FInfo;
  72.         NewRefNum, ULRefNum, Count, StuffRef: integer;
  73.         logicalEOF, HowManyUsers: longint;
  74.         Today: DateTimeRec;
  75.         ResourceHandle: StringHandle;
  76.         StuffResource: Handle;
  77.         NowSecs: longint;
  78.  
  79. {-----------------------------------------------------------------    }
  80.  
  81. procedure NoMem;
  82.  
  83.     var
  84.         MemDialog: DialogPtr;
  85.         MemItem: integer;
  86.  
  87.     begin
  88.         MemDialog := GetNewDialog(1003, nil, Pointer(-1));
  89.         SetPort(MemDialog);
  90.         FrameDItem(MemDialog, Ok);
  91.         DrawDialog(MemDialog);
  92.         ModalDialog(nil, MemItem);
  93.         repeat
  94.         until MemItem = 1;
  95.         DisposDialog(MemDialog);
  96.         ExitToShell;
  97.     end;
  98.  
  99. {------------------------------}
  100.  
  101. function BigString (Number: integer): string;
  102.  
  103. { Function changes two-digit number to a two-character string.           }
  104.  
  105.     begin
  106.         BigString := concat(Int2Char(Number div 10), Int2Char(Number mod 10))
  107.     end;
  108.  
  109. { ------------------------------------------------------ }
  110.  
  111. procedure SortUserLog;
  112.  
  113.     type
  114.         UserPointer = ^UserRecord;
  115.         UserHandle = ^UserPointer;
  116.         UserArray = array[1..1] of UserHandle;
  117.         UArrayPtr = ^UserArray;
  118.         UArrayHdl = ^UArrayPtr;
  119.         SortRecord = record
  120.                 IndexNo: integer;
  121.                 IndexString: packed array[1..7] of char;
  122.             end;
  123.         SortArray = array[1..1] of SortRecord;
  124.         SortArrayPtr = ^SortArray;
  125.         SortArrayHdl = ^SortArrayPtr;
  126.  
  127.     var
  128.         UserLogHdl: UArrayHdl;
  129.         myArrayHdl: SortArrayHdl;
  130.         UserCount1, UserCount2, SortedUser, ULRef: integer;
  131.         HeadCount: longint;
  132.  
  133.     procedure QuickSort (Start, Finish: integer; var TheArray: SortArrayHdl);
  134.  
  135. {    Sorts array Users by Clearance+Date field using QuickSort    }
  136.  
  137.         var
  138.             Left, Right: integer;
  139.             StarterValue: packed array[1..7] of char;
  140.             Temp: SortRecord;
  141.  
  142.         begin
  143.             Left := Start;
  144.             Right := Finish;
  145.             StarterValue := TheArray^^[(Start + Finish) div 2].IndexString;    {    Pick a starter    }
  146.             repeat
  147.                 while TheArray^^[Left].IndexString < StarterValue do
  148.                     Left := Left + 1;    {    Find a bigger value on the left    }
  149.                 while StarterValue < TheArray^^[Right].IndexString do
  150.                     Right := Right - 1;    {    Find a smaller value on the right    }
  151.                 if Left <= Right then
  152.                     begin    {If we haven't gone too far...    }
  153.                         Temp := TheArray^^[Left];
  154.                         TheArray^^[Left] := TheArray^^[Right];
  155.                         TheArray^^[Right] := Temp;
  156.                         Left := Left + 1;
  157.                         Right := Right - 1
  158.                     end;    {    then    }
  159.             until Right <= Left;
  160.             if Start < Right then
  161.                 QuickSort(Start, Right, TheArray);
  162.             if Left < Finish then
  163.                 QuickSort(Left, Finish, TheArray)
  164.         end;    {    procedure QuickSort    }
  165.  
  166.     begin
  167.         ULRecSize := SizeOf(UserRecord);
  168.         Err := FSOpen(ULPath, vRefNum, ULRef);
  169.         Err := SetFPos(ULRef, fsFromStart, ULRecSize);    {    Sysop is at seek position zero, so we skip it    }
  170.         Err := GetEOF(ULRef, logicalEOF);
  171.         HeadCount := logicalEOF div ULRecSize;
  172.         UserCount1 := 1;
  173.         myArrayHdl := nil;
  174.         UserLogHdl := nil;
  175.         myArrayHdl := SortArrayHdl(NewHandle(SizeOf(SortArray) + ((HeadCount - 1) * SizeOf(SortRecord))));
  176.         if myArrayHdl <> nil then
  177.             UserLogHdl := UArrayHdl(NewHandle(SizeOf(UserArray) + ((HeadCount - 1) * SizeOf(UserRecord))));
  178.         if (myArrayHdl <> nil) & (UserLogHdl <> nil) then
  179.             begin
  180.                 MoveHHi(Handle(myArrayHdl));
  181.                 HLock(Handle(myArrayHdl));
  182.                 MoveHHi(Handle(UserLogHdl));
  183.                 HLock(Handle(UserLogHdl));
  184.                 if (HeadCount > 2) then
  185.                     begin
  186.                         for UserCount1 := 2 to HeadCount do        {    skip 1 to allow for missing sysop        }
  187.                             begin
  188.                                 UserLogHdl^^[UserCount1] := UserHandle(NewHandle(ULRecSize));
  189.                                 Err := FSRead(ULRef, ULRecSize, Ptr(UserLogHdl^^[UserCount1]^));
  190.                                 myArrayHdl^^[UserCount1].IndexNo := UserCount1;
  191.                                 myArrayHdl^^[UserCount1].IndexString := concat(UserLogHdl^^[UserCount1]^^.TCMRRF[2], UserLogHdl^^[UserCount1]^^.DateLastCalled);
  192.                             end;        {    for UserCount1 := 1 to HeadCount - 1    }
  193.  
  194.                         QuickSort(2, HeadCount, myArrayHdl);
  195.  
  196.                         Err := SetFPos(ULRef, fsFromStart, ULRecSize);    {    Sysop is at seek position zero, so we skip it    }
  197.  
  198.                         for UserCount2 := HeadCount downto 2 do    {    Write in reverse to get proper order    }
  199.                             begin
  200.                                 SortedUser := myArrayHdl^^[UserCount2].IndexNo;
  201.                                 Err := FSWrite(ULRef, ULRecSize, @UserLogHdl^^[SortedUser]^^);
  202.                                 DisposHandle(Handle(UserLogHdl^^[SortedUser]));
  203.                             end;        {    for UserCount2 := UserCount1 downto 1    }
  204.  
  205.                         if myArrayHdl <> nil then
  206.                             begin
  207.                                 HUnlock(Handle(myArrayHdl));
  208.                                 DisposHandle(Handle(myArrayHdl));
  209.                                 myArrayHdl := nil;
  210.                             end;
  211.                         if UserLogHdl <> nil then
  212.                             begin
  213.                                 HUnlock(Handle(UserLogHdl));
  214.                                 DisposHandle(Handle(UserLogHdl));
  215.                                 UserLogHdl := nil;
  216.                             end;
  217.                     end         {    if (myArrayHdl <> nil) & (UserLogHdl <> nil)    }
  218.                 else
  219.                     NoMem;
  220.                 Err := FSClose(ULRef)
  221.             end        {    (HeadCount > 2)    }
  222.     end;
  223.  
  224. { ------------------------------------------------------ }
  225.  
  226. function UserHasExpired (DateOfLastCall: WhenCalled; DaysAllowed: longint): boolean;
  227.  
  228.     var
  229.         UserDTR: DateTimeRec;
  230.         UserSecs: longint;
  231.  
  232.     begin
  233.         UserDTR.Year := BitAnd(ord(DateOfLastCall[1]), 255) + 1900;
  234.         UserDTR.Month := BitAnd(ord(DateOfLastCall[2]), 255);
  235.         UserDTR.Day := BitAnd(ord(DateOfLastCall[3]), 255);
  236.         UserDTR.Hour := 0;
  237.         UserDTR.Minute := 0;
  238.         UserDTR.Second := 0;
  239.         Date2Secs(UserDTR, UserSecs);
  240.         if (NowSecs - UserSecs) > (DAYSECS * DaysAllowed) then
  241.             UserHasExpired := true
  242.         else
  243.             UserHasExpired := false
  244.     end;
  245.  
  246. { ------------------------------------------------------ }
  247.  
  248. procedure GetFromAndPW (var From, PW: str255);
  249.  
  250.     var
  251.         Counter: integer;
  252.  
  253.     begin
  254.         From := '';
  255.         for Counter := 2 to ord(ThisUser.CallingFromAndPW[1]) + 1 do
  256.             From := concat(From, ThisUser.CallingFromAndPW[Counter]);
  257.         PW := '';
  258.         for Counter := 33 to ord(ThisUser.CallingFromAndPW[32]) + 32 do
  259.             PW := concat(PW, ThisUser.CallingFromAndPW[Counter]);
  260.     end;
  261.  
  262. { ------------------------------------------------------ }
  263.  
  264. procedure WriteDeleteLog (ReasonDeleted: str255);
  265.  
  266.     var
  267.         DeleteRef, Counter: integer;
  268.         ULDeleteFile, Password, FromString, LogString: str255;
  269.  
  270.     begin
  271.         if MultiFinder then
  272.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  273.         ULDeleteFile := concat(DefaultsPtr^.DBackupPath, 'Users Deleted');
  274.         Err := FSOpen(ULDeleteFile, vRefNum, DeleteRef);
  275.         if Err <> NoErr then
  276.             begin
  277.                 Err := Create(ULDeleteFile, vRefNum, DefaultsPtr^.TEXTType, 'TEXT');
  278.                 Err := FSOpen(ULDeleteFile, vRefNum, DeleteRef);
  279.                 Err := WrLn(DeleteRef, '           Calls    Last       UL   DL  Pub  Pri  Lev  Min   Reason');
  280.             end;
  281.         if Err = NoErr then
  282.             begin
  283.                 Err := SetFPos(DeleteRef, FSFromLEOF, 0);
  284.                 GetFromAndPW(FromString, Password);
  285.                 with ThisUser do
  286.                     begin
  287.                         LogString := concat(FirstName, ' ', LastName, ' from ', FromString);
  288.                         LogString := concat(LogString, '    [', Password, ']', ENDLINE);
  289.                         LogString := concat(LogString, StripTime(DateString), '    ', StringOf(NumberOfCalls : 4), '  ');
  290.                         LogString := concat(LogString, BigString(ord(DateLastCalled[2])), '/');
  291.                         LogString := concat(LogString, BigString(ord(DateLastCalled[3])), '/');
  292.                         LogString := concat(LogString, BigString(ord(DateLastCalled[1])), '   ');
  293.                         LogString := concat(LogString, StringOf(Uploads : 4), ' ');
  294.                         LogString := concat(LogString, StringOf(Downloads : 4), ' ');
  295.                         LogString := concat(LogString, StringOf(PubMsg : 4), ' ');
  296.                         LogString := concat(LogString, StringOf(PrivMsg : 4), '  ');
  297.                         LogString := concat(LogString, StringOf(ord(TCMRRF[2]) : 3), '  ');
  298.                         LogString := concat(LogString, StringOf(ord(TCMRRF[1]) : 3), '   ', ReasonDeleted)
  299.                     end;    {with ThisUser}
  300.                 Err := WrLn(DeleteRef, LogString)
  301.             end;
  302.         Err := FSClose(DeleteRef)
  303.     end;
  304.  
  305. { ------------------------------------------------------ }
  306.  
  307. procedure BackUserLog;
  308.  
  309.     const
  310.         MaxBadNames = 100;
  311.  
  312.     var
  313.         FilePointer: Ptr;
  314.         ULCounter: longint;
  315.         BadNameFile, HowManyBadNames, Counter, i, ULCopyRefNum: integer;
  316.         NewULog, TheBAK: str255;
  317.         BadNames: array[1..MaxBadNames] of string[15];
  318.         GoodUser, isDeleted: boolean;
  319.         ReasonDeleted, SitName: str255;
  320.         HowManyCharacters, tempDirRef, tempVRef, tempLong, MsgNumAdjust, NewFileLength: longint;
  321.  
  322.     begin
  323.         if MultiFinder then
  324.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  325.         ULRecSize := SizeOf(UserRecord);
  326.         GetDateTime(NowSecs);
  327.         for Counter := 1 to MaxBadNames do
  328.             BadNames[Counter] := '';
  329.         Err := FSOpen(concat(gDefaultpath, 'Bad User Names'), vRefNum, BadNameFile);
  330.         Counter := 1;
  331.         while (Err = NoErr) & (Counter < MaxBadNames + 1) do
  332.             begin
  333.                 Err := ReadALine(BadNameFile, BadNames[Counter]);
  334.                 if BadNames[Counter] = '' then
  335.                     leave;
  336.                 Counter := succ(Counter);
  337.             end;
  338.         HowManyBadNames := Counter - 1;
  339.         Err := FSClose(BadNameFile);
  340.         if MultiFinder then
  341.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  342.         NewULog := concat(ULPath, '.$$$');
  343.         TheBAK := concat(ULPath, '.BAK');
  344.         while FileExists(NewULog) do
  345.             Err := FSDelete(NewULog, vRefNum);
  346.         Err := Create(NewULog, vRefNum, 'ULED', 'ULOG');
  347.         Err := FSOpen(NewULog, vRefNum, NewRefNum);
  348.         Err := SetFPos(NewRefNum, fsFromStart, 0);
  349.         Err := FSOpen(ULPath, vRefNum, ULRefNum);
  350.         Err := GetEOF(ULRefNum, logicalEOF);
  351.         Err := SetFPos(ULRefNum, fsFromStart, 0);
  352.         HowManyUsers := logicalEOF div ULRecSize;
  353.         for ULCounter := 1 to HowManyUsers do
  354.             with DefaultsPtr^ do
  355.                 begin
  356.                     if MultiFinder then
  357.                         IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  358.                     Err := FSRead(ULRefNum, ULRecSize, @ThisUser);
  359.                     ReasonDeleted := 'Unknown';
  360.                     isDeleted := BitAnd(ord(ThisUser.TCMRRF[6]), DELETED) = DELETED;
  361.                     if DoChangeLevel then
  362.                         if (ThisUser.TCMRRF[2] = chr(ChangeLevel)) then
  363.                             begin
  364.                                 GoodUser := true;
  365.                                 for Counter := 1 to HowManyBadNames do
  366.                                     if (EqualString(ThisUser.FirstName, BadNames[Counter], false, false)) | (EqualString(ThisUser.LastName, BadNames[Counter], false, false)) then
  367.                                         begin
  368.                                             GoodUser := false;
  369.                                             ThisUser.TCMRRF[1] := chr(0);            {    zero time        }
  370.                                             ThisUser.TCMRRF[2] := chr(0);            {    zero access    }
  371.                                             ThisUser.TCMRRF[6] := chr(DELETED);        {    delete        }
  372.                                             ReasonDeleted := 'Bad Name';
  373.                                             isDeleted := true;
  374.                                             leave
  375.                                         end;
  376.                                 if GoodUser then
  377.                                     begin
  378.                                         ThisUser.TCMRRF[1] := chr(ChangeToMin);
  379.                                         ThisUser.TCMRRF[2] := chr(ChangeToLevel);
  380.                                     end
  381.                             end;        {    if (ThisUser.TCMRRF[2] = chr(Newcomer))        }
  382.                     if DefaultsPtr^.ZeroMin then
  383.                         ThisUser.TCMRRF[3] := chr(0);
  384.                     if (ord(ThisUser.TCMRRF[2]) <= CheckLevel) & (ULCounter <> 1) then
  385.                         begin
  386.                             if KillOld then
  387.                                 if UserHasExpired(ThisUser.DateLastCalled, InactiveDays) then
  388.                                     begin
  389.                                         ThisUser.TCMRRF[6] := chr(DELETED);
  390.                                         isDeleted := true;
  391.                                         ReasonDeleted := 'Inactive'
  392.                                     end;
  393.                             if KillOldOneCalls then
  394.                                 if (ThisUser.NumberOfCalls < 2) then
  395.                                     if UserHasExpired(ThisUser.DateLastCalled, OneCallDays) then
  396.                                         if ((ThisUser.Uploads + ThisUser.Downloads + ThisUser.PrivMsg + ThisUser.PubMsg) < 1) then
  397.                                             begin
  398.                                                 ThisUser.TCMRRF[6] := chr(DELETED);
  399.                                                 isDeleted := true;
  400.                                                 ReasonDeleted := 'One-Timer'
  401.                                             end;
  402.                         end;        {    if (ord(ThisUser.TCMRRF[2]) <= CheckLevLong) & (ULCounter <> 1)        }
  403.                     if MultiFinder then
  404.                         IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  405.                     if UseVetFlag & (ThisUser.NumberOfCalls > VetCalls) then
  406.                         begin
  407.                             tempLong := ord(ThisUser.MRRF[6 - ((VetFlag - 1) div 8)]);
  408.                             if SetVetFlag then
  409.                                 BSET(tempLong, (VetFlag - 1) mod 8)
  410.                             else
  411.                                 BCLR(tempLong, (VetFlag - 1) mod 8);
  412.                             ThisUser.MRRF[6 - ((VetFlag - 1) div 8)] := chr(tempLong mod 256);
  413.                         end; {if UseVetFlag & (ThisUser.NumberOfCalls > VetCalls)}
  414.                     if (ThisUser.TCMRRF[2] = chr(DeleteLevel)) & DeleteByLevel & (ReasonDeleted <> 'Bad Name') then
  415.                         ReasonDeleted := 'Bad Level';
  416. {    Next section checks TCMRFF byte 2 to see if clearance is valid        }
  417.                     if (ThisUser.TCMRRF[2] <> chr(DeleteLevel)) | (not DeleteByLevel) then
  418.                         begin
  419.                             if (not isDeleted) | (not SkipDeletes) then
  420.                                 begin
  421.                                     if (DefaultsPtr^.Renumber) & (ThisUser.HiMsgRead > 1) then
  422.                                         begin
  423.                                             MoveHHi(Handle(myMNAHdl));
  424.                                             HLock(Handle(myMNAHdl));
  425.                                             for MsgNumAdjust := 1 to myMNAHdl^^.HowMany do
  426.                                                 begin
  427.                                                     if (ThisUser.HiMsgRead < myMNAHdl^^.OldNumbers[MsgNumAdjust]) then
  428.                                                         begin
  429.                                                             ThisUser.HiMsgRead := pred(MsgNumAdjust);
  430.                                                             leave
  431.                                                         end
  432.                                                     else if ThisUser.HiMsgRead = myMNAHdl^^.OldNumbers[MsgNumAdjust] then
  433.                                                         begin
  434.                                                             ThisUser.HiMsgRead := MsgNumAdjust;
  435.                                                             leave
  436.                                                         end;
  437.                                                 end;        {    for MsgNumAdjust := 1 to myMNAHdl^^.HowMany    }
  438.                                             if ThisUser.HiMsgRead < 0 then
  439.                                                 ThisUser.HiMsgRead := 0
  440.                                             else if ThisUser.HiMsgRead > myMNAHdl^^.HowMany then
  441.                                                 ThisUser.HiMsgRead := myMNAHdl^^.HowMany;
  442.                                         end;        {    if (DefaultsPtr^.Renumber) & (ThisUser.HiMsgRead > 1)    }
  443.                                     HUnlock(Handle(myMNAHdl));
  444.                                     Err := FSWrite(NewRefNum, ULRecSize, @ThisUser);
  445.                                 end; {if (not isDeleted) | (not SkipDeletes)}
  446.                         end; {if (ThisUser.TCMRRF[2] <> chr(DeleteLevel)) | (not DeleteByLevel)}
  447.                     if isDeleted & SkipDeletes & LogDeletes then
  448.                         WriteDeleteLog(ReasonDeleted);
  449.                 end;    {for ULCounter := 1 to HowManyUsers do }
  450.         Err := GetFPos(NewRefNum, NewFileLength);
  451.         Err := SetEOF(NewRefNum, NewFileLength);
  452.         Err := FSClose(ULRefNum);
  453.         Err := FSClose(NewRefNum);
  454.         while FileExists(TheBAK) do
  455.             Err := FSDelete(TheBAK, vRefNum);            {    Delete old Userlog.BAK            }
  456.         Err := Rename(ULPath, vRefNum, TheBAK);        {    Rename Userlog to Userlog.BAK        }
  457.         while FileExists(ULPath) do
  458.             Err := FSDelete(ULPath, vRefNum);            {    Delete old Userlog                }
  459.         Err := Rename(NewULog, vRefNum, ULPath);        {    Rename Userlog.$$$ to Userlog        }
  460.  
  461.         if myMNAHdl <> nil then
  462.             begin
  463.                 DisposHandle(Handle(myMNAHdl));
  464.                 myMNAHdl := nil
  465.             end;
  466.  
  467.         if DefaultsPtr^.DBackupMode in [StuffNone..StuffBestGuess] then
  468.             while FileExists(TheBAK) do
  469.                 Err := FSDelete(TheBAK, vRefNum)        {    Delete Userlog.BAK -- it's stuffed    }
  470.         else
  471.             begin    {need to restore UserLog to original file so aliases in System 7 work        }
  472.                 Err := CopyFile(TheBAK, NewULog);        {    copy UL.BAK into UL.$$$            }
  473.                 while FileExists(TheBAK) do
  474.                     Err := FSDelete(TheBAK, vRefNum);        {    Delete old Userlog.BAK            }
  475.                 Err := CopyFile(ULPath, TheBAK);        {    copy UL into UL.BAK                }
  476.                 while FileExists(ULPath) do
  477.                     Err := FSDelete(ULPath, vRefNum);        {    delete UL                        }
  478.                 Err := Rename(TheBAK, vRefNum, ULPath);    {    rename UL.BAK to UL                }
  479.                 Err := Rename(NewULog, vRefNum, TheBAK);    {    rename UL.$$$ to UL.BAK            }
  480.             end;
  481.         if MultiFinder then
  482.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  483.     end;
  484.  
  485. { ------------------------------------------------------ }
  486.  
  487. procedure ProcessUserLog;
  488.  
  489.     var
  490.         TempString: str255;
  491.  
  492.     begin
  493.         if DefaultsPtr^.ProcessUL then
  494.             begin
  495.                 if MultiFinder then
  496.                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  497.                 TextFont(0);
  498.                 TextSize(12);
  499.                 ForeColor(BlueColor);
  500.                 TempString := 'mehitabel: doing users…';
  501.                 EraseRect(StatusRect);
  502.                 TextBox(Pointer(ord(@TempString) + 1), length(TempString), StatusRect, teJustLeft);
  503.                 TempString := 'backing';
  504.                 EraseRect(MsgNoRect);
  505.                 TextFont(Geneva);
  506.                 TextSize(9);
  507.                 ForeColor(RedColor);
  508.                 TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
  509.                 TextFont(0);
  510.                 TextSize(12);
  511.                 ForeColor(BlueColor);
  512.                 BackUserLog;
  513.                 TempString := 'sorting';
  514.                 EraseRect(MsgNoRect);
  515.                 TextFont(Geneva);
  516.                 TextSize(9);
  517.                 ForeColor(RedColor);
  518.                 TextBox(Pointer(ord(@TempString) + 1), length(TempString), MsgNoRect, teJustRight);
  519.                 if DefaultsPtr^.SortUserLog then
  520.                     SortUserLog;
  521.                 if DefaultsPtr^.WriteToTabby then
  522.                     begin
  523.                         if MultiFinder then
  524.                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  525.                         TimeStamp;
  526.                         Err := FSOpen(concat(gDefaultpath, 'Tabby:Tabby Log'), DefaultVol, TLogRef);
  527.                         Err := SetFPos(TLogRef, fsFromLEOF, 0);
  528.                         Err := WrLn(TLogRef, concat(DateString, ' mehitabel - ', stringOf(HowManyUsers : 1), ' users processed'));
  529.                         Err := FSClose(TLogRef)
  530.                     end
  531.             end
  532.     end;
  533.  
  534. { ------------------------------------------------------ }
  535.  
  536. end.